#include "Cliente.h"

/**
 * Inicializa un participante con su log, y sus handlers de señales.
 */
Cliente::Cliente(string apodo):sem(FuncionesComunes::ConvertirACharPointer(ARCHIVO_SEMAFORO), 1)
,log(FuncionesComunes::GetNombreLog())
{
	id = getpid();
	nombre = apodo;
	SignalHandler::getInstance()->registrarHandler(SIGINT, &sigint_handler);
}

/**
 * Crea un canal para enviar mensajes y uno para recibirlos. Cuando se recibe la señal ctrl + c
 * se finaliza el proceso y se elimina al cliente de la conversación.
 */
void Cliente::ejecutar()
{
	string nombreCanalParticipante = FuncionesComunes::GedIdCanalServidor()+ FuncionesComunes::Separador + nombre;
	string iniciaConversacion = FuncionesComunes::GetIdAbrirCanal(id,nombre);
	string finConversacion = FuncionesComunes::GetIdCerrarCanal(id,nombre);
	this->activarModoDebug(false);
	Fifo canalServidor(FuncionesComunes::GedIdCanalServidor().c_str());
	pid_t pid = fork();
	if (pid == 0) {
		leerMensajes(nombreCanalParticipante + "down");
		exit(0);
	} else {

		char *abrirCanalParticipante = FuncionesComunes::ConvertirACharPointer(iniciaConversacion);
		canalServidor.escribir(abrirCanalParticipante, strlen(abrirCanalParticipante));
		sem.wait();
		log.write("[Cliente] El participante "+ nombre + " tiene como pid " +  FuncionesComunes::ConvertirAString(id));
		sem.signal();
		enviarMensaje(canalServidor);
		sem.wait();
		log.write("[Cliente]" + FuncionesComunes::GetIdEscribirLog(id,nombre) + " Envío la señal SIGINT al hijo. ");
		sem.signal();
		kill(pid, SIGINT);
		sem.wait();
		log.write("[Cliente]" + FuncionesComunes::GetIdEscribirLog(id,nombre) + " Envié la señal SIGINT al hijo. ");
		sem.signal();
		wait(NULL);
		sem.wait();
		log.write("[Cliente] El participante " + nombreCanalParticipante + " abandona la conversacion.");
		sem.signal();

		char *cerrarCanalParticipante = FuncionesComunes::ConvertirACharPointer(finConversacion);
		canalServidor.escribir(cerrarCanalParticipante, strlen(cerrarCanalParticipante));
		canalServidor.cerrar();
		sem.eliminar();
		SignalHandler::destruir();
	}
}

/**
 * Lee los mensajes del Fifo "nombreCanal" y los muestra por pantalla.
 */
void Cliente::leerMensajes(string nombreCanal) {
	//SIGINT_Handler sigint;
	//SignalHandler::getInstance()->registrarHandler(SIGINT, &sigint);
	int id = getpid();
	string linea = FuncionesComunes::GetIdEscribirLog(id,nombre + "_hijo");
	while (sigint_handler.getGracefulQuit() == 0) {
		Fifo canalEntrante (FuncionesComunes::ConvertirACharPointer(nombreCanal));
		Mensaje mensaje;
		sem.wait();
		log.write("[Cliente] "+ linea +  " Estoy listo para leer");
		sem.signal();
		int bytesLeidos = canalEntrante.leer(mensaje.linea, 100);
		mensaje.linea[bytesLeidos] = '\0';
		sem.wait();
		string s = mensaje.linea;
		log.write("[Cliente] " + linea + " El participante " + nombre +" leyó: " + s);
		sem.signal();
		cout << mensaje.linea << endl;
		canalEntrante.cerrar();
	}
	sem.wait();
	log.write("[Cliente]" + linea + " Terminé el proceso leer.");
	sem.signal();
}

/**
 * Envía mensajes a partir del Fifo canal
 */
void Cliente::enviarMensaje(Fifo &canal) {
		cout<<"Escribir mensaje: "<<endl;
		cout<<"[ " + nombre +" dice: ]"<<endl;
	while (sigint_handler.getGracefulQuit() == 0) {
		char linea[100];
		cin.getline(linea, 100);
		string s (linea);

		if(!s.empty()){
			string sub = FuncionesComunes::GetIdEnviarMensaje(id,nombre);
			sub += s;
			strcpy(linea, FuncionesComunes::ConvertirACharPointer(sub));
			sem.wait();
			log.write("[Cliente] El participante " + FuncionesComunes::GetIdEscribirLog(id,nombre)  +" escribió: " + sub);
			sem.signal();
			canal.escribir(linea, strlen(linea));
		}
		//delete linea;
	}
}

void Cliente::activarModoDebug(bool activar){
	log.activeDebug(activar);
}

Cliente::~Cliente()
{
}
